#!/bin/bash
##这是一个仅用于Centos7.X及Centos8.x发行版安装部署K8S集群的脚本
##By:梯度科技-刘某
#
#
##定义字体效果
#红色背景
red_bg='\e[41;33;1m'
#红色字体
red_zt='\e[1;31m'
#绿色背景
green_bg='\033[0;32;1m'
#绿色字体
green_zt='\e[1;32m'
#关闭效果
end='\033[0m'
#字体闪烁
ss='\033[05m'
#消隐
sy='\33[08m'
##常用语句定义区
e_s(){
	echo -e "${green_bg}${ss}${green_bg}正在进入...${end}${end}${end}\n${red_zt}${1}...${end}"
}
e_info(){
	echo -e "${red_zt}${1}:${end}${green_zt}${2}${end}"
}
cheks(){
	echo -e "${red_zt}正在检测${1}...${end}"
}
e_g(){
	echo -e "${green_zt}${1}${end}"
}
e_r_g_z(){
	echo -e "${red_zt}${1}${end}${green_zt}${2}${end}${green_zt}${3}${end}"
}
e_r(){
	echo -e "${red_zt}${1}${end}"
}
e_r_b(){
	echo -e "${red_bg}${1}${end}"
}
e_r_z_bg(){
	echo -e "${red_zt}${1}${end}${red_bg}${2}${end}"
}
input(){
	echo -e "${red_zt}${1}${end}"
	read $2
}
def_chek(){
	#一参为检测项
	#二参为等级判断
	if [[ "$?" == '0' ]];then
		e_info "${1}" "[SUCCESS]"
	else
		e_r_z_bg  "${1}:" "[[FAILD]"
		if [[ "${2}" == 'q' ]];then
			e_r_b "严重故障,程序强行终止"
			kill -9 $$
		else
			e_r "该错误可能会影响搭建,建议终止安装"
			read err
		fi
	fi
}
def_chek_null(){
	if [[ -z "$1" ]];then
		e_r_b "${2}参数不允许设置为空"
		exit 22
	fi
}
#########################################预安装信息配置-开始###########################################
def_host_ip(){
	e_r "请输入${1}节点IP地址:"
	read IP
	def_chek_null "$IP" "${1}节点IP地址"
	if [[ "$2" == "n" ]];then
		echo -e "${red_zt}请输入Master节点IP地址${end}"
		read master_ip
		def_chek_null "$master_ip}" "Master节点IP地址"
		if [[ $IP == $master_ip ]];then
			e_r "Master节点IP地址与Node节点一致,请仔细检查配置再重新执行"
			e_r_b "bash $0"
			exit 2
		else
			e_r "正在检测Master节点IP"
			ping ${master_ip} -c 5 > /dev/null
			def_chek "Master节点连接"
			input "是否复制master节点的hosts文件到本地[y/n]" "shp"
			if [[ "$shp" == "y" || "$shp" == "Y" ]];then
				scp ${master_ip}:/etc/hosts /etc/
			else
				e_g "跳过hosts文件同步"
			fi
			echo "${IP} ${1}" >>  /etc/hosts
		fi
	else
		master_ip="$IP"
	fi
	e_r "正在检测本机IP..."
	ping ${IP} -c 5 > /dev/null
	def_chek "IP连接检测" "q"
}
def_host_name(){
	input "请输入本机主机名:[Default ${1}]" "names"
	if [[ -z "$names" ]];then
                names="$1"
		e_info "已使用默认主机名" "$names"
        else
                e_g "已使用自定义主机名:${red_zt}${names}${end}"
	fi
	if [[ "${1}" == "master" ]];then
		Master_server="$names"
	fi
	hostnamectl set-hostname $names
}
def_hosts_matser(){
	input "请输入Node节点数量" "hs"
	rm -f info.conf
	if [[ -z "$hs" || "$hs" == "0" ]];then
		e_g "本次未设置Node节点"
	else
		for((i=1;i<=$hs;i++));do
			input "请输入第${i}个节点主机名" "n_n"
			input "请输入${n_n}节点IP地址[不做网络连通性检测]" "n_ip"
			echo -e "${n_ip} ${n_n}" >> /etc/hosts 
			echo -e "${n_ip} ${n_n}" >> info.conf
		done
	fi
}
#检查当前环境是否满足脚本要求
sys_chek(){
	cheks "当前登录用户权限"
	if [[ "$UID" == "0" ]];then
		e_info "用户权限" "[SUCCESS]"
	else
		e_info "用户权限" "[FAILD]"
	fi
	cheks "网络连接"
	ping 119.29.29.29 -c 5 > /dev/null
	def_chek "网络连接" "q"
	cheks "DNS配置"
	ping baidu.com -c 5 > /dev/null
	def_chek "DNS配置" "q"
	osBit=`getconf LONG_BIT`
        if [ "${osBit}" != '64' ];then
                e_r_b "抱歉,暂时不支持32位系统"
                exit 32
        fi
	if [[ -f '/etc/os-release' ]];then
		os_ver=`awk -F= '/^NAME/{print $2}' /etc/os-release | sed 's/"//g'| awk '{print $1}'`
		if [[ "$os_ver" == "CentOS" || "$os_ver" == "Centos" ]];then
			s=`sudo awk '{print $4}' /etc/redhat-release | cut -b 1`
			if [[ "$s" == "7" || "$s" == "8" ]];then
				e_r_g_z "系统版本:" "[SCUUESS]"
				if [[ "$s" == "7" ]];then
					export p_i="yum"
				elif [[ "$s" == "8" ]];then
					export p_i="dnf"
				else
					e_r "不存在的"
				fi
			else
				e_r_z_bg "系统版本:" "[FAILD]"
				exit 78
			fi
		else
			e_r_z_bg "系统版本:" "[FAILD]"
		fi
	else
		 e_r_z_bg "系统版本:" "[FAILD]"
	fi
}
#获取安装节点信息
sys_info(){
	cpus=`cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l`
	if [[ "$cpus" < "2" ]];then
		e_r_g_z "本机CPU数量无法满足Master最低要求[最低2核]\n" "已默认设置本节点为Node节点"
	else
		e_r_g_z "请选择本机节点类型\n" "[1]Master\n" "[2]Node [Default]"
		read types
	fi
	e_r_g_z "是否初始化主机名映射文件[y/n]\n" "建议初始化[defalut y]"
	read inits
	if [[ "$inits" == 'n' ]];then
		e_r_g_z "保留现有hosts文件"
	else
		echo -e "127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\n::1         localhost localhost.localdomain localhost6 localhost6.localdomain6" > /etc/hosts
	fi
	input "是否服务安装完成就拉取相关镜像[y/n];默认[n]" "pull"
	if [[ "$types" == '1' ]];then
		jiedian='master'
		jj='m'
		#def_host_name  "master"
		def_hosts_matser		
		input "是否生成初始化K8S脚本[y/n];默认[n]" "ik8s"
	else
		jiedian='node'
		jj='n'
		input "请输入Matser节点主机名" "Master_server"
	fi
	def_host_ip "$jiedian" "$jj"
	def_host_name  "$jiedian" "$jj"
}
install_info(){
	e_info "当前系统版本" "CentOS${s}"
	e_info "当前主机类型" "$jiedian"
	e_info "Master节点IP" "$master_ip"
	e_info "Master主机名" "$Master_server"
	if [[ -z "$hs" ]];then
		e_info "当前主机IP" "$IP"
	else
		for((i=1;i<=$hs;i++));do
			ip=`cat info.conf | sed -n "$i"p | awk '{print $1}'`
			hostn=`cat info.conf | sed -n "$i"p | awk '{print $2}'`
			e_info "${hostn}主机IP" "${ip}"
		done
	fi
	echo "$master_ip $Master_server" >> /etc/hosts
	if [[ "$ik8s" == "y" || "$ik8s" == "Y" ]];then
		ik='是'
	else
		ik="否"
	fi
	e_info "是否生成初始化K8S服务脚本" "$ik"
	if [[ "$pull" == "y" || "$pull" == "Y" ]];then
		 pl="是"
	else
		pl="否"
	fi
	e_info "服务安装完成立即拉取镜像" "$ik"
	e_s "按回车开始安装"
	read Y
}
yum_bak(){
	if [[ -d "/yum_bak/" ]];then
		e_g "源文件已备份"
	else
		e_r "正在备份源文件"
		mkdir -p /yum_bak/
		mv /etc/yum.repos.d/* /yum_bak/
		e_info "源备份" "[SCUUESS]"
	fi
}
yum_os(){
	yum_bak
	if [[ "$s" == "7" ]];then
		curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 
		def_chek "系统源配置文件写入"
	elif [[ "$s" == '8' ]];then
		curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo 
		def_chek "系统源配置文件写入"
	else
		e_r "啊哦,无法检测出本机系统版本"
	fi
	yum_docker 
}
yum_docker(){
	$p_i install -y yum-utils device-mapper-persistent-data lvm2 -q 
	yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 
	def_chek "Dcoker源配置文件写入"
	yum_k8s 
}
yum_k8s(){
	cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
	def_chek "kubernetes源配置文件写入"
	sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/*.repo
	$p_i clean all 
	$p_i makecache -y
	def_chek "源索引建立"
}
sysconfig(){
	if [[ "$s" == '7' ]];then
		yum install ntpdate -qy
		def_chek "NTPDATE安装"
	fi
	if [[ -f '/usr/bin/ntpdate' ]];then
		for((i=1;i>=3;i++));do
			ntpdate time.windows.com
			def_chek "第${i}次时间同步"
		done
	fi
	e_r "正在关闭防火墙"
	systemctl stop firewalld
	def_chek "防火墙关闭" 
	systemctl disable firewalld
	e_r "正在关闭Selinux"
	setenforce 0
        if [[ -f "/etc/selinux/config" ]];then
                sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
        fi
        if [[ -f "/etc/sysconfig/selinux" ]];then
                sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/sysconfig/selinux
        fi
	e_r "正在关闭SWAP"
	swapoff -a
	def_chek "SWAP临时关闭"
	sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab
	echo -e "net.bridge.bridge-nf-call-ip6tables = 1\nnet.bridge.bridge-nf-call-iptables = 1\nnet.ipv4.ip_forward = 1" > /etc/sysctl.conf
	def_chek "内核转发配置参数写入"
        sysctl -p > /dev/null
	sysctl --system
}
service_unstall(){
	input "是否卸载${1}\t[y/n]" "unstall"
	if [[ "$unstall" == 'Y' || "$unstall" == 'y' ]];then
		if [[ "$1" == "docker" ]];then
			r="docker-ce containerd.io container-selinux"
		elif [[ "$1" == "kubelet" ]];then
			r="kubelet kubectl kubeadm"
		else
			echo 'dd'
		fi
		$p_i remove -y $r
		def_chek "${1}卸载"
	else
		e_g "跳过卸载"
	fi
}
service_chek(){
	if [[ -f "/usr/bin/$1" ]];then
		e_r "${1}服务已安装"
		service_unstall "$1"
	else
		rpms=`rpm -qa | $1`
		if [[ -n "$rpms" ]];then
			e_r "${1}服务已安装"
			service_unstall "$1"
		fi
	fi
}
service_ver(){
	Dcoker_C_ver=`docker version | grep Version | awk '{print $2}' |sed -n 1p`
	Dcoker_S_ver=`docker version | grep Version | awk '{print $2}' |sed -n 2p`
	kubeamd_ver=`kubeadm version |awk '{print $5}' |sed -e 's/GitVersion:\"//' -e 's/\".*//'`
	e_info "当前Docker客户端版本" "$Dcoker_C_ver"
	e_info "当前Docker服务端版本" "$Dcoker_S_ver"
	e_info "当前kubernetes 版 本" "$kubeamd_ver"
}
install_docker(){
	service_chek "docker"
        re=`$p_i list docker-ce --showduplicates|sort -r | awk '{print $2}' | awk 'NR>6{print}'|sed 's/base://'| awk NF |sed 's/3://'`
	for i in $re;do
		e_g $i
	done
	e_r "请选择一个docker版本并粘贴\n默认安装最新版"
	e_r_b "低版本很有可能安装失败,建议安装较新版本"
        read docker_ver
        if [[ -z "$docker_ver" ]];then
		e_g "已选择安装最新版本"
                dockers="docker-ce"
        else
		if [[ -z `echo $re | grep "$docker_ver"` ]];then
			e_r_b "好像你输入的版本并不在上面的列表中"
			e_g "已默认安装最新版"
			dockers="docker-ce"
		else
			e_g "已选择安装${docker_ver}"
                	dockers="docker-ce-${docker_ver}"
		fi
        fi
	if [[ "$s" == "8" ]];then
		 $p_i install -y https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/edge/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
		 def_chek "containerd安装"
	fi
	e_r "正在安装Docker..."
	$p_i install -y $dockers -q
	def_chek "Dcoker安装"
	install_k8s
}
install_k8s(){
	service_chek "kubelet"
	$p_i install -y kubelet kubectl kubeadm -q
	def_chek "K8S安装"
}
install_services(){
	install_docker
	services="docker kubelet"
	for i in $services;do
		systemctl start $i
		def_chek "${i}启动"
		systemctl enable $i > /dev/null
		def_chek "${i}设置开机启动"
	done
	e_g "服务安装完成"
	service_ver
	$p_i install -q -y bash-completion
	def_chek "自动补全工具"
	source /usr/share/bash-completion/bash_completion
	auto="kubectl kubeadm"
	for i in $auto;do
		source <($i completion bash)
		echo "source <($i completion bash)" >> ~/.bashrc
	done
}
images_pull(){
	images172="registry.aliyuncs.com/google_containers/kube-apiserver
registry.aliyuncs.com/google_containers/kube-controller-manager
registry.aliyuncs.com/google_containers/kube-scheduler
registry.aliyuncs.com/google_containers/kube-proxy"
	for i in $images172;do
	        images="${i}:v1.17.2"
	        docker pull ${images}
	done
	images="registry.aliyuncs.com/google_containers/coredns:1.6.5
registry.aliyuncs.com/google_containers/etcd:3.4.3-0
registry.aliyuncs.com/google_containers/pause:3.1"
	for i in $images;do
        	docker pull $i
	done
}
init_k8s(){
	mkdir -p /init/
	echo "
	ver=`kubeadm version|awk '{print $5}'|sed "s/[^0-9|\.]//g"|awk 'NR==1{print}'`
	echo -e \"K8s version is \" \"v${ver}\"
	echo -e \"Master IP is\" \"${master_ip}\"
	swapoff -a
	echo \"正在初始化K8S\"
	echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
	kubeadm init --apiserver-advertise-address=${master_ip} \
    --image-repository registry.aliyuncs.com/google_containers \
    --kubernetes-version v\${ver} \
    --service-cidr=10.2.11.0/16 \
    --pod-network-cidr=10.244.0.0/16 > /dev/null
	mkdir -p \$HOME/.kube
	cp -i /etc/kubernetes/admin.conf \$HOME/.kube/config
	chown \$(id -u):\$(id -g) \$HOME/.kube/config
	kubectl apply -f https://xypj-1252147235.cos.ap-guangzhou.myqcloud.com/kube-flannel.yaml >/dev/null
	kubeadm token create --print-join-command > z
	zs=`cat z`
	echo  \"当前集群节点信息如下\"
	kubectl get nodes
	echo -e \"请在Node节点执行下面的指令以加入此Master节点\"  \"\n\$zs\"
	echo -e \"如需获取注册指令,请在本节点执行下面的命令\n\" \"kubeadm token create --print-join-command\" " > /init/k8s.sh
}
services_config(){
	mkdir -p  /etc/docker/
	echo -e "{\n\t\"exec-opts\": [\"native.cgroupdriver=systemd\"],\n\t\"registry-mirrors\": [\"http://hub-mirror.c.163.com\"]\n}" > /etc/docker/daemon.json
	systemctl daemon-reload
	systemctl restart docker
	def_chek "Docker镜像加速地址配置"
	if [[ "$jiedian" == "node" ]];then
		if [[ "$pull" == "y" || "$pull" == "Y" ]];then
			images_pull
			def_chek "镜像拉取"
		else
			e_g "跳过镜像下载,请在控制节点执行下面的命令获取注册命令"
		fi
		e_g "kubeadm token create --print-join-command"
	elif [[ "$jiedian" == "master" ]];then
		if [[ "$pull" == "y" || "$pull" == "Y" ]];then
                        images_pull
                        def_chek "镜像拉取"
                else
                        e_g "跳过镜像拉取"
                fi
		if [[ "$ik8s" == "y" || "$ik8s" == "Y" ]];then
			init_k8s
			echo -e  "${red_zt}请手动执行下面的指令进行初始化${end}\n${green_bg}bash /init/k8s.sh${end}"
			su -
		else
			e_r "请自行初始化K8S服务"
		fi

	else
		e_r_b "永远相信美好的事情即将发生"
	fi
}
#########进入安装流程..................
e_s "[第一步]检查网络及用户权限"
sys_chek
e_s "[第二步]配置预安装配置信息"
sys_info
e_s "[第三步]预安装配置信息确认"
install_info
e_s "[第四步]配置相关源仓库"
yum_os 
e_s "[第五步]配置系统相关安全设置"
sysconfig
e_s "[第六步]服务安装"
install_services
e_s "[第七步]服务配置"
services_config
#########################################预安装信息配置-结束###########################################
